#include "LD3320_Driver.h"

UDOUBLE nMp3Size = 0;				// mp3 size
UDOUBLE nMp3Pos = 0;				// mp3 current position
UBYTE 	nAsrStatus = 0;				// Record the status of the ASR	
UBYTE 	nLD_Mode = LD_MODE_IDLE;	// Record the status of LD3320(ASR or Play Sound)
UBYTE 	bMp3Play = 0;				// Record the status of audio player
UBYTE 	ucRegVal;					// Interrupt request number
UBYTE 	ucHighInt;					// Intterrupt enable status
UBYTE 	ucLowInt;					// Intterrupt enable status
UBYTE 	ucStatus;					// FIFO status
UBYTE 	ucSPVol = 5;				// Speaker volume, MAX=15 MIN=0	
FILE 	*fp;

static UBYTE LD_AsrAddKey(void);
static void LD_Init_Common(void);
static void LD_ReloadMp3Data(void);
static UBYTE LD_Check_ASRBusyFlag(void);
static void LD_WriteReg(UBYTE data1,UBYTE data2);
static UBYTE LD_ReadReg(UBYTE reg_add);
static void LD_Init_ASR(void);
static UBYTE LD_AsrRun(void);

/********************************************************************************
function:	
				Interrupt signal processing(ASR and Audio Player)
********************************************************************************/
void ProcessInt()//中断完成 ASR或者MP3播放
{
	UBYTE nAsrResCount = 0;		
	ucRegVal = LD_ReadReg(0x2B);//中断请求编号
	ucHighInt = LD_ReadReg(0x29);	// interrupt enable flag 中断允许
	ucLowInt = LD_ReadReg(0x02);	// interrupt enable flag FIFO中断允许
	LD_WriteReg(0x29, 0);			// interrupt disenable 中断不允许
	LD_WriteReg(0x02, 0);			// interrupt disenable FIFO不允许
	if(nLD_Mode == LD_MODE_ASR_RUN) {
		printf("LD3320_Driver:ProcessInt: ---------------ASR---------------\r\n");
		//The interruption caused by speech recognition
		//(There is sound input, and there is interruption whether the recognition is successful or failed)
		if((ucRegVal & 0x10) && LD_ReadReg(0xb2)==0x21 && LD_ReadReg(0xbf)==0x35) {//一次ASR正常结束
			nAsrResCount = LD_ReadReg(0xba);//记录语音识别候选
			if(nAsrResCount>0 && nAsrResCount<=4) {//有识别候选
				printf("LD3320_Driver:ProcessInt: ASR SUCCESSFUL \r\n");
				nAsrStatus = LD_ASR_FOUNDOK;//记录ASR状态
			}
			else {//识别失败
				printf("LD3320_Driver:ProcessInt: ASR UNSUCCESSFUL \r\n");
				nAsrStatus = LD_ASR_FOUNDZERO;
			}	
		}
		else {//语音识别暂无结果
			printf("LD3320_Driver: ProcessInt: No ASR \r\n");
			nAsrStatus = LD_ASR_FOUNDZERO;
		}			
		LD_WriteReg(0x2b, 0);//清空中断请求
		LD_WriteReg(0x1c, 0);//ADC不可用
		return;
	}	
	printf("LD3320_Driver:ProcessInt: --------------PLAY MP3--------------\r\n");
	// Play MP3 to produce 3 kinkd of intterupt
	// A. play over
	// B. data send over
	// C. Data will be used up and sent
	if(LD_ReadReg(0xBA) & CAUSE_MP3_SONG_END) {//播放器已经发现mp3的结尾
		// A. play over
		LD_WriteReg(0x2B, 0);//清空中断请求
		LD_WriteReg(0xBA, 0);//清空中断辅助信息	
		LD_WriteReg(0xBC, 0);//清空MP3数据结束标志	
		LD_WriteReg(0x08, 1);//清除FIFO_DATA
		LD_WriteReg(0x08, 0);//再写入0
		LD_WriteReg(0x33, 0);//播放完结束，写入00h
		if(bMp3Play == 1){
			fclose(fp);
		}
		printf("LD3320_Driver:ProcessInt: play over \r\n");
		bMp3Play = 0;			// play status
		//printf("fclose fp\n");
		return;
	}
	if(nMp3Pos >= nMp3Size) {//MP3文件播放完
		// B. data send over
		LD_WriteReg(0xBC, 0x01);//data voer
		LD_WriteReg(0x29, 0x10);//同步中断允许
		return;	
	}
	// C. Data will be used up and sent
	//printf("MP3 mode3\n");	
	LD_ReloadMp3Data();//播放MP3文件
	//printf("MP3 mode3 Reload finsh\n");
	LD_WriteReg(0x29, ucHighInt);//恢复中断允许 
	LD_WriteReg(0x02, ucLowInt);//恢复FIFO中断	
}

/********************************************************************************
function:	
				Run ASR
********************************************************************************/
UBYTE LD_ASR(void)//添加识别字，开始识别
{
	UBYTE i = 0;
	UBYTE asrflag = 0;
	for (i=0; i<5; i++) {						//run ASR try 5 times
		LD_Init_ASR();								//init ASR
		Driver_Delay_ms(100);
		if (LD_AsrAddKey() == 0) {		//Add fixed to LD3320 添加失败
			printf("LD3320_Driver:LD_ASR: ERROR!!! LD_AsrAddKey\r\n");
			LD_init();									//ERROR,Reset LD3320
			Driver_Delay_ms(50);	
			continue;
		}
		Driver_Delay_ms(10);
		if (LD_AsrRun() == 0) {				//start ASR
			printf("LD3320_Driver:LD_ASR: ERROR!!! LD_AsrRun\r\n");
			LD_init();									//ERROR,Reset LD3320
			Driver_Delay_ms(50);
			continue;
		}
		asrflag = 1;
		break;						
	}	
	printf("LD3320_Driver:LD_ASR: RunASR\r\n");
	return asrflag;
}

/********************************************************************************
function:	
				Start play
********************************************************************************/
void LD_play()//播放MP3
{
	nMp3Pos = 0;
	bMp3Play = 1;
	
	if(nMp3Pos >=  nMp3Size)//MP3文件读取完毕
		return; 

	LD_ReloadMp3Data();//

	LD_WriteReg(0xBA, 0x00);//中断辅助信息
	LD_WriteReg(0x17, 0x48);//activate DSP  激活DSP
	LD_WriteReg(0x33, 0x01);//play mp3
	LD_WriteReg(0x29, 0x04);//FIFO interrupt allowed
	LD_WriteReg(0x02, 0x01);//FIFO_DATA interrupt allowed 
	LD_WriteReg(0x85, 0x5A);//内部反馈设置 改变内部增益
}

/********************************************************************************
function:	
				LD3320 hardware init
********************************************************************************/
void LD_init(void)//重启
{
	RST_1;
	Driver_Delay_ms(100);
	RST_0;
	Driver_Delay_ms(100);
	RST_1;
	
	Driver_Delay_ms(100);
	CS_0;
	Driver_Delay_ms(100);
	CS_1;		
	Driver_Delay_ms(100);
	
	printf("LD3320_Driver:LD_init: LD reset over\r\n");
	
	// LD_ReadReg(0x06);
	// LD_WriteReg(0x35, 0x33);
	// LD_WriteReg(0x1b, 0x55);
	// LD_WriteReg(0xb3, 0xaa);
	// printf(" %x \n", LD_ReadReg(0x35));	
	// printf(" %x \n", LD_ReadReg(0x1b));	
	// printf(" %x \n", LD_ReadReg(0xb3));
	
	// printf(" %x \n", LD_ReadReg(0x06));
	// printf(" %x \n", LD_ReadReg(0x06));
	// printf(" %x \n", LD_ReadReg(0x35));
	// printf(" %x \n", LD_ReadReg(0xb3));
}

/********************************************************************************
function:	
				Adjust headset volume
note:
				MAX=15 MIN=0
********************************************************************************/
void LD_Adjust_Volume(UBYTE val)//耳机音量调节
{
	val = ((15-val)&0x0f) << 2;
	LD_WriteReg(0x8e, val | 0xc1); 	//volume  喇叭输出音量
	LD_WriteReg(0x87, 0x78);		//accept adjust  喇叭音量调节激发
}

/********************************************************************************
function:	
				Get LD3320 return value
********************************************************************************/
UBYTE LD_GetResult(void)
{
	return LD_ReadReg(0xc5);//读取ASR结果
}

/********************************************************************************
function:	
				Add  ASR KeyWord
********************************************************************************/
static UBYTE LD_AsrAddKey(void)//ASR识别关键词
{
	UBYTE k, flag;
	UBYTE nAsrAddLength;
	#define DATE_A 3  
	#define DATE_B 30	

	UBYTE  sRecog[DATE_A][DATE_B] = {		//add commond,use pinying
	 			"fa duan xin",\
				"bo da dian hua",\
		
																	};	
	UBYTE  pCode[DATE_A] = {						//add commond code to do the commond
				CODE_SMS,	\
				CODE_CALL,	\
		
															};	
	flag = 1;
	for(k=0; k<DATE_A; k++) {						//write data to LD3320	
		if(LD_Check_ASRBusyFlag() == 0) {
			flag = 0;//添加识别字失败
			break;
		}
		LD_WriteReg(0xc1, pCode[k]);//添加识别字索引
		LD_WriteReg(0xc3, 0);//识别字添加时写入00
		LD_WriteReg(0x08, 0x04);//清除FIFO_EXT
		Driver_Delay_ms(1);
		LD_WriteReg(0x08, 0x00);//清除指定FIFO后再写入一次00H
		Driver_Delay_ms(1);
		for (nAsrAddLength=0; nAsrAddLength<DATE_B; nAsrAddLength++) {
			if (sRecog[k][nAsrAddLength] == 0)//一条识别句 存储完成
				break;
			LD_WriteReg(0x5, sRecog[k][nAsrAddLength]);//FIFO_EXT数据口
		}
		LD_WriteReg(0xb9, nAsrAddLength);//当前添加识别句的字符串长度
		LD_WriteReg(0xb2, 0xff);//DSP忙闲状态
		LD_WriteReg(0x37, 0x04);//通知DSP要添加一项识别句
	}	 
	return flag;
}

/********************************************************************************
function:	
				Reload mp3 data
********************************************************************************/
static void LD_ReloadMp3Data()//播放MP3
{
	//printf("ReloadMp3\n");
	UBYTE val;
	ucStatus = LD_ReadReg(0x06);//读FIFO状态
	while (!(ucStatus&MASK_FIFO_STATUS_AFULL) && (nMp3Pos<nMp3Size)) {//FIFO_DATA可写 并且MP3文件未读完
		//printf("nMp3Pos++\n");
		/*if(!(ucStatus&MASK_FIFO_STATUS_AFULL))
		{
			printf("FIFO_DATA Yes\n");
		}*/
		nMp3Pos++;
		val = fgetc(fp);
		LD_WriteReg(0x01, val);
		ucStatus = LD_ReadReg(0x06);
	}
}

/********************************************************************************
function:	
				Common init
********************************************************************************/
static void LD_Init_Common(void)//通用初始化
{
	bMp3Play = 0;
	
	LD_ReadReg(0x06);  
	LD_WriteReg(0x17, 0x35);//软复位 
	Driver_Delay_ms(20);
	LD_ReadReg(0x06);  

	LD_WriteReg(0x89, 0x03);//模拟电路初始化  
	Driver_Delay_ms(20);
	LD_WriteReg(0xCF, 0x43);//内部省电模式设置   
	Driver_Delay_ms(20);
	LD_WriteReg(0xCB, 0x02);
	
	/*PLL setting*/
	LD_WriteReg(0x11, LD_PLL_11);//时钟频率设置    10  
	if (nLD_Mode == LD_MODE_MP3) {//MP3模式
		LD_WriteReg(0x1E, 0x00);//ADC专用控制 初始化 
		LD_WriteReg(0x19, LD_PLL_MP3_19);//时钟设置   
		LD_WriteReg(0x1B, LD_PLL_MP3_1B);//时钟设置   
		LD_WriteReg(0x1D, LD_PLL_MP3_1D);//时钟设置
	}
	else {//ASR
		LD_WriteReg(0x1E,0x00);//ADC专用控制 初始化
		LD_WriteReg(0x19, LD_PLL_ASR_19); 
		LD_WriteReg(0x1B, LD_PLL_ASR_1B);		
		LD_WriteReg(0x1D, LD_PLL_ASR_1D);
	}
	Driver_Delay_ms(20);
	
	LD_WriteReg(0xCD, 0x04);//允许DSP休眠
	LD_WriteReg(0x17, 0x4c);//使DSP休眠 
	Driver_Delay_ms(20);
	LD_WriteReg(0xB9, 0x00);//当前添加识别句的字符串长度 初始化
	LD_WriteReg(0xCF, 0x4F);//内部省电模式设置 
	LD_WriteReg(0x6F, 0xFF);// 
}

/********************************************************************************
function:	
				ASR init
********************************************************************************/
static void LD_Init_ASR(void)//ASR初始化
{
	nLD_Mode=LD_MODE_ASR_RUN;
	LD_Init_Common();

	LD_WriteReg(0xBD, 0x00);//ASR模块
	LD_WriteReg(0x17, 0x48);//激活DSP	
	Driver_Delay_ms(20);
	
	LD_WriteReg(0x3C, 0x80);//FIFO_EXT下限低8位    
	LD_WriteReg(0x3E, 0x07);//FIFO_EXT下限高8位
	LD_WriteReg(0x38, 0xff);//FIFO_EXT上限低8位    
	LD_WriteReg(0x3A, 0x07);//FIFO_EXT上限高8位
	Driver_Delay_ms(20);
	
	LD_WriteReg(0x40, 0);//FIFO_EXT MCU水线低8位          
	LD_WriteReg(0x42, 8);//FIFO_EXT MCU水线高8位
	LD_WriteReg(0x44, 0);//FIFO_EXT DSP水线低8位
	LD_WriteReg(0x46, 8);//FIFO_EXT DSP水线高8位 
	Driver_Delay_ms(20);
}

/********************************************************************************
function:	
				MP3 player init
********************************************************************************/
void LD_Init_MP3()//MP3初始化
{
	nLD_Mode = LD_MODE_MP3; 
	LD_Init_Common();

	LD_WriteReg(0xBD, 0x02);//启动为MP3模块
	LD_WriteReg(0x17, 0x48);//激活DSP
	Driver_Delay_ms(20);
	LD_WriteReg(0x85, 0x52);//内部反馈设置 
	LD_WriteReg(0x8F, 0x00);//LineOut选择  
	LD_WriteReg(0x81, 0x00);//左耳机音量 最大音量
	LD_WriteReg(0x83, 0x00);//右耳机音量
	LD_WriteReg(0x8E, 0xff);//喇叭输出音量 最大音量
	LD_WriteReg(0x8D, 0xff);//内部增益控制
	Driver_Delay_ms(20);
	LD_WriteReg(0x87, 0xff);//模拟电路初始化
	LD_WriteReg(0x89, 0xff);//模拟电路初始化
	Driver_Delay_ms(20);
	LD_WriteReg(0x22, 0x00);//FIFO_DATA下限低8位    
	LD_WriteReg(0x23, 0x00);//FIFO_DATA下限高8位
	LD_WriteReg(0x20, 0xef);//FIFO_DATA上限低8位    
	LD_WriteReg(0x21, 0x07);//FIFO_DATA上限高8位
	LD_WriteReg(0x24, 0x77);//FIFO_DATA MCU水线低8位          
	LD_WriteReg(0x25, 0x03);//FIFO_DATA MCU水线高8位
	LD_WriteReg(0x26, 0xbb);//FIFO_DATA DSP水线低8位    
	LD_WriteReg(0x27, 0x01);//FIFO_DATA DSP水线高8位 
}

/********************************************************************************
function:	
				Begin to ASR
********************************************************************************/
static UBYTE LD_AsrRun(void)//ASR前的准备
{
	LD_WriteReg(0x35, MIC_VOL);//麦克风音量 测试板工作时使用的设置是43H
	LD_WriteReg(0x1C, 0x09);//ADC开关控制 
	LD_WriteReg(0xBD, 0x20);//初始化控制寄存器
	LD_WriteReg(0x08, 0x01);//清除FIFO_DATA
	Driver_Delay_ms(20);
	LD_WriteReg(0x08, 0x00);//清除指定FIFO后再写入一次00H
	Driver_Delay_ms(20);

	if(LD_Check_ASRBusyFlag() == 0)//ASR繁忙
		return 0;
	
	LD_WriteReg(0xB2, 0xff);//DSP闲忙状态	
	LD_WriteReg(0x37, 0x06);//语音识别控制命令下发寄存器 通知DSP开始识别语音
	LD_WriteReg(0x37, 0x06);//
	Driver_Delay_ms(20);
	LD_WriteReg(0x1C, 0x0b);//麦克风输入ADC通道可用
	LD_WriteReg(0x29, 0x10);//同步中断允许
	LD_WriteReg(0xBD, 0x00);//启动，为ASR模块
	return 1;
}

/********************************************************************************
function:	
				Check ASR state
********************************************************************************/
static UBYTE LD_Check_ASRBusyFlag(void)//检查ASR状态
{
	UBYTE j;
	UBYTE flag = 0;
	for (j=0; j<10; j++) {//查询10次
		if (LD_ReadReg(0xb2) == 0x21) {//DSP空闲			
			flag = 1;
			break;
		}
		Driver_Delay_ms(10);
		//printf("ERROR!!! ASR Busy\r\n");
	}
	return flag;
}

/********************************************************************************
function:	
				Write data to LD3320 reg
********************************************************************************/
static void LD_WriteReg(UBYTE data1,UBYTE data2)
{
	CS_0;
	WR_0;
	spi_send_byte(0x04);
	spi_send_byte(data1);
	spi_send_byte(data2);
	// printf("writereg is %x, %x\r\n", data1, data2);
	CS_1;
}

/********************************************************************************
function:	
				Read data from LD3320 reg
********************************************************************************/
static UBYTE LD_ReadReg(UBYTE reg_add)
{
	UBYTE i;
	CS_0;
	WR_0;
	spi_send_byte(0x05);
	spi_send_byte(reg_add);
	i = spi_send_byte(0x00);
	// printf("readreg is %x \r\n", i);
	CS_1;
	return(i);
}


